/*
 * logapi.c
 *
 *  Created on: 2011-3-8
 *      Author: minorityee
 */

#include "logapi.h"
#include "common_def.h"
#include <time.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>

#ifndef WIN32
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif

DECLARE_LOGLEVEL_STR(arrLogLevelStr);

static int32_t __WriteLogFileStdIO(const char* cszFile,
		const char* cszLogPrefix, const char* cszFormat, va_list ap);
#ifndef WIN32
static int32_t __WriteLogFileSYNC(const char* cszFile, const char* cszLogPrefix,
		const char* cszFormat, va_list ap);
#endif
static int32_t __WriteLogFileStderr(const char* cszLogPrefix,
		const char* cszFormat, va_list ap);


int32_t WriteLog(const char* cszLogFilePrefix, IOType io, LogLevel enmLogLv,
		const char* cszFormat, ...)
{
	assert(NULL != cszFormat);
	assert(!(NULL == cszLogFilePrefix && enmStderr != io));
	if (NULL == cszLogFilePrefix && enmStderr != io)
		return E_NULLPOINTER;
	if (NULL == cszFormat)
		return E_NULLPOINTER;

	time_t rawtime = { 0 };
	time(&rawtime);
	struct tm* pCurrTime = NULL;
	pCurrTime = localtime(&rawtime);
	assert(NULL != pCurrTime);
	if (NULL == pCurrTime)
		return S_FALSE;

	char szLogPrefix[enmMaxLogLen] = { 0 };
	//pattern:  LogPrefix yyyy-mm-dd hh:mm:ss[loglevel]
	snprintf(szLogPrefix, enmMaxLogLen, "%04d-%02d-%02d %02d:%02d:%02d %s",
			pCurrTime->tm_year + 1900, pCurrTime->tm_mon + 1,
			pCurrTime->tm_mday, pCurrTime->tm_hour, pCurrTime->tm_min,
			pCurrTime->tm_sec, arrLogLevelStr[enmLogLv]);

	int ret = S_OK;
	char szFileName[enmMaxLogFileNameLen] = { 0 };
	va_list argp;
	va_start(argp, cszFormat);
	if (enmStderr == io)
	{
		ret = __WriteLogFileStderr(szLogPrefix, cszFormat, argp);
		goto LAB_END;
	}

	// generate log file name
	snprintf(szFileName, enmMaxLogFileNameLen, "%s_%04d%02d%02d.log",
			cszLogFilePrefix, pCurrTime->tm_year + 1900, pCurrTime->tm_mon + 1,
			pCurrTime->tm_mday);

	switch (io)
	{
#ifndef WIN32
	case enmSYNC:
		ret = __WriteLogFileSYNC(szFileName, szLogPrefix, cszFormat, argp);
		break;
#endif
	case enmNONBLOCK:
	case enmStdIO:
	default:
		ret = __WriteLogFileStdIO(szFileName, szLogPrefix, cszFormat, argp);
	}
LAB_END:
	va_end(argp);
	return ret;
}

int32_t VWriteLog( const char* 	cszLogFilePrefix,
				  IOType		io,
				  LogLevel		enmLogLv,
				  const char*	cszFormat,
				  va_list		argp	)
{
	assert(NULL != cszFormat);
	assert(!(NULL == cszLogFilePrefix && enmStderr != io));
	if (NULL == cszLogFilePrefix && enmStderr != io)
		return E_NULLPOINTER;
	if (NULL == cszFormat)
		return E_NULLPOINTER;

	time_t rawtime = { 0 };
	time(&rawtime);
	struct tm* pCurrTime = NULL;
	pCurrTime = localtime(&rawtime);
	assert(NULL != pCurrTime);
	if (NULL == pCurrTime)
		return S_FALSE;

	char szLogPrefix[enmMaxLogLen] = { 0 };
	char szFileName[enmMaxLogFileNameLen] = { 0 };
	//pattern:  LogPrefix yyyy-mm-dd hh:mm:ss[loglevel]
	snprintf(szLogPrefix, enmMaxLogLen, "%04d-%02d-%02d %02d:%02d:%02d %s",
			pCurrTime->tm_year + 1900, pCurrTime->tm_mon + 1,
			pCurrTime->tm_mday, pCurrTime->tm_hour, pCurrTime->tm_min,
			pCurrTime->tm_sec, arrLogLevelStr[enmLogLv]);

	int ret = S_OK;
	if (enmStderr == io)
	{
		ret = __WriteLogFileStderr(szLogPrefix, cszFormat, argp);
		goto LAB_END;
	}

	// generate log file name
	snprintf(szFileName, enmMaxLogFileNameLen, "%s_%04d%02d%02d.log",
			cszLogFilePrefix, pCurrTime->tm_year + 1900, pCurrTime->tm_mon + 1,
			pCurrTime->tm_mday);

	switch (io)
	{
#ifndef WIN32
	case enmSYNC:
		ret = __WriteLogFileSYNC(szFileName, szLogPrefix, cszFormat, argp);
		break;
#endif
	case enmNONBLOCK:
	case enmStdIO:
	default:
		ret = __WriteLogFileStdIO(szFileName, szLogPrefix, cszFormat, argp);
	}
LAB_END:
	return ret;
}



LogLevel StrToLogLevel(const char *cszLogLevel)
{
	if (0 == strcmp(cszLogLevel, "DEBUG"))
	{
		return enmLogLevel_DEBUG;
	}
	if (0 == strcmp(cszLogLevel, "INFO"))
	{
		return enmLogLevel_INFO;
	}
	if (0 == strcmp(cszLogLevel, "WARN"))
	{
		return enmLogLevel_WARN;
	}
	if (0 == strcmp(cszLogLevel, "ERROR"))
	{
		return enmLogLevel_ERROR;
	}
	if (0 == strcmp(cszLogLevel, "FATAL"))
	{
		return enmLogLevel_FATAL;
	}
	return enmLogLevel_INVALID;
}

int32_t __WriteLogFileStdIO(const char* cszFile, const char* cszLogPrefix,
		const char* cszFormat, va_list ap)
{
	FILE* file = fopen(cszFile, "a+");
	//	assert(NULL != file);
	if (NULL == file)
	{
		fprintf(stderr, "file %s not open!\n", cszFile);
		return S_FALSE;
	}
	fprintf(file, "%s", cszLogPrefix);
	vfprintf(file, cszFormat, ap);
	fprintf(file, "\n");
	fclose(file);
	return S_OK;
}

#ifndef WIN32
int32_t __WriteLogFileSYNC(const char* cszFile, const char* cszLogPrefix,
		const char* cszFormat, va_list ap)
{
	char szLogContent[enmMaxLogLen - enmMaxLogPrefixLen] = { 0 };
	char szLog[enmMaxLogLen] = { 0 };
	snprintf(szLog, sizeof(szLog), cszLogPrefix);
	vsprintf(szLogContent, cszFormat, ap);
	strncat(szLog, szLogContent, sizeof(szLog));
	strncat(szLog, "\n", sizeof(szLog));
	szLog[sizeof(szLog) - 1] = '\0';

	int fd = open(cszFile, O_SYNC | O_APPEND | O_CREAT | O_WRONLY,
			S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH /*664*/);
	write(fd, szLog, strlen(szLog));
	close(fd);
	return S_OK;
}
#endif

int32_t __WriteLogFileStderr(const char* cszLogPrefix, const char* cszFormat,
		va_list ap)
{
	fprintf(stderr, "%s", cszLogPrefix);
	vfprintf(stderr, cszFormat, ap);
	fprintf(stderr, "\n");
	return S_OK;
}
